package com.example.demo.dao.base;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;

/**
 * 2025/9/30
 */
public class QueryWrapper<T> {
    private final List<String> conditions = new ArrayList<>();
    private final List<Object> params = new ArrayList<>();
    private final List<String> orderBys = new ArrayList<>();

    public QueryWrapper<T> eq(String column, Object value) {
        this.checkColumnAndParam(column, value);
        conditions.add(column + " = ?");
        params.add(value);
        return this;
    }

    public <R> QueryWrapper<T> eq(SFunction<T, R> column, Object value) {
        return eq(LambdaUtils.getColumn(column), value);
    }

    public QueryWrapper<T> ne(String column, Object value) {
        this.checkColumnAndParam(column, value);
        conditions.add(column + " != ?");
        params.add(value);
        return this;
    }

    public <R> QueryWrapper<T> ne(SFunction<T, R> column, Object value) {
        return ne(LambdaUtils.getColumn(column), value);
    }

    public QueryWrapper<T> like(String column, Object value) {
        this.checkColumnAndParam(column, value);
        conditions.add(column + " LIKE ?");
        params.add("%" + value + "%");
        return this;
    }

    public <R> QueryWrapper<T> like(SFunction<T, R> column, Object value) {
        return like(LambdaUtils.getColumn(column), value);
    }

    public QueryWrapper<T> gt(String column, Object value) {
        this.checkColumnAndParam(column, value);
        conditions.add(column + " > ?");
        params.add(value);
        return this;
    }

    public <R> QueryWrapper<T> gt(SFunction<T, R> column, Object value) {
        return gt(LambdaUtils.getColumn(column), value);
    }

    public QueryWrapper<T> lt(String column, Object value) {
        this.checkColumnAndParam(column, value);
        conditions.add(column + " < ?");
        params.add(value);
        return this;
    }

    public <R> QueryWrapper<T> lt(SFunction<T, R> column, Object value) {
        return lt(LambdaUtils.getColumn(column), value);
    }

    public QueryWrapper<T> ge(String column, Object value) {
        this.checkColumnAndParam(column, value);
        conditions.add(column + " >= ?");
        params.add(value);
        return this;
    }

    public <R> QueryWrapper<T> ge(SFunction<T, R> column, Object value) {
        return ge(LambdaUtils.getColumn(column), value);
    }

    public QueryWrapper<T> le(String column, Object value) {
        this.checkColumnAndParam(column, value);
        conditions.add(column + " <= ?");
        params.add(value);
        return this;
    }

    public <R> QueryWrapper<T> le(SFunction<T, R> column, Object value) {
        return le(LambdaUtils.getColumn(column), value);
    }

    public QueryWrapper<T> in(String column, List<?> values) {
        this.checkColumnAndParam(column, values);
        StringJoiner sj = new StringJoiner(",", "(", ")");
        for (int i = 0; i < values.size(); i++) {
            sj.add("?");
            params.add(values.get(i));
        }
        conditions.add(column + " IN " + sj.toString());
        return this;
    }

    public <R> QueryWrapper<T> in(SFunction<T, R> column, List<?> values) {
        return in(LambdaUtils.getColumn(column), values);
    }

    public QueryWrapper<T> inSql(String column, Object value) {
        this.checkColumnAndParam(column, value);
        conditions.add(column + " IN (" + value + ")");
        return this;
    }

    public <R> QueryWrapper<T> inSql(SFunction<T, R> column, List<?> values) {
        return in(LambdaUtils.getColumn(column), values);
    }

    public QueryWrapper<T> isNull(String column) {
        conditions.add(column + " is NULL");
        return this;
    }

    public <R> QueryWrapper<T> isNull(SFunction<T, R> column) {
        return isNull(LambdaUtils.getColumn(column));
    }

    public QueryWrapper<T> isNotNull(String column) {
        conditions.add(column + " is NOT NULL");
        return this;
    }

    public <R> QueryWrapper<T> isNotNull(SFunction<T, R> column) {
        return isNotNull(LambdaUtils.getColumn(column));
    }

    public QueryWrapper<T> orderByAsc(String column) {
        orderBys.add(column + " ASC");
        return this;
    }

    public <R> QueryWrapper<T> orderByAsc(SFunction<T, R> column) {
        return orderByAsc(LambdaUtils.getColumn(column));
    }

    public QueryWrapper<T> orderByDesc(String column) {
        orderBys.add(column + " DESC");
        return this;
    }

    public <R> QueryWrapper<T> orderByDesc(SFunction<T, R> column) {
        return orderByDesc(LambdaUtils.getColumn(column));
    }

    public String getWhereClause() {
        if (conditions.isEmpty()) {
            return "";
        }
        return " WHERE " + String.join(" AND ", conditions);
    }

    public List<Object> getParams() {
        return new ArrayList<>(params);
    }

    public String getOrderByClause() {
        if (orderBys.isEmpty()) {
            return "";
        }
        return " ORDER BY " + String.join(", ", orderBys);
    }

    /**
     * 校验参数字段
     * @param column column
     * @param value value
     */
    private void checkColumnAndParam(String column, Object value){
        if (Objects.isNull(column) || column.isBlank()) {
            throw new IllegalArgumentException("参数字段不能为空");
        }
        if (Objects.isNull(value)) {
            throw new IllegalArgumentException("字段值不能为空");
        }
    }
}
